{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "80b6eb4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain_core.prompts.few_shot import FewShotPromptTemplate"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c6822000",
   "metadata": {},
   "source": [
    "# FewShotPromptTemplate例子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "02bf3c62",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===生成的提示词===\n",
      "text='句子：小猫在草地上追蝴蝶\\n动物：小猫、蝴蝶\\n\\n句子：大象和长颈鹿在动物园里散步\\n动物：大象、长颈鹿\\n\\n句子：鱼缸里的金鱼和乌龟很安静\\n动物：金鱼、乌龟\\n\\n句子：老虎和猴子在森林里玩耍\\n动物：'\n"
     ]
    }
   ],
   "source": [
    "# 导入基础模板和少样本示例模板\n",
    "from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate\n",
    "\n",
    "# 1、创建示例集合（少样本学习的样本）\n",
    "# 每个示例是一个字典，包含输入和期望输出，用于告诉模型\"如何做\"\n",
    "examples = [\n",
    "    {\"input\": \"小猫在草地上追蝴蝶\", \"output\": \"小猫、蝴蝶\"},\n",
    "    {\"input\": \"大象和长颈鹿在动物园里散步\", \"output\": \"大象、长颈鹿\"},\n",
    "    {\"input\": \"鱼缸里的金鱼和乌龟很安静\", \"output\": \"金鱼、乌龟\"}\n",
    "]\n",
    "\n",
    "# 2、创建示例模板（定义单个示例的格式）\n",
    "# 用于统一所有示例的展示形式，让模型能识别\"输入是什么样，输出应该是什么样\"\n",
    "example_prompt = PromptTemplate.from_template(\n",
    "    template=\"句子：{input}\\n动物：{output}\"  # 固定格式：左侧是输入句子，右侧是提取的动物\n",
    ")\n",
    "\n",
    "# 3、创建少样本提示模板（组合示例和新问题）\n",
    "# 作用：将示例集合、示例格式、新问题按顺序拼接，形成完整提示\n",
    "prompt = FewShotPromptTemplate(\n",
    "    examples=examples,  # 传入准备好的示例集合\n",
    "    example_prompt=example_prompt,  # 传入单个示例的格式模板\n",
    "    suffix=\"句子：{input}\\n动物：\",  # 新问题的格式（放在示例后面，等待模型输出）\n",
    "    input_variables=[\"input\"]  # 新问题的变量名（与suffix中的{input}对应）\n",
    ")\n",
    "\n",
    "# 4、传入新问题，生成最终提示\n",
    "# 这里的\"input\"是要处理的新句子，模型会参考前面的示例进行提取\n",
    "final_prompt = prompt.invoke({\"input\": \"老虎和猴子在森林里玩耍\"})\n",
    "\n",
    "# 打印结果，查看完整提示内容\n",
    "print(\"===生成的提示词===\")\n",
    "print(final_prompt)\n",
    "# ===生成的提示词===\n",
    "# 句子：小猫在草地上追蝴蝶\n",
    "# 动物：小猫、蝴蝶\n",
    "\n",
    "# 句子：大象和长颈鹿在动物园里散步\n",
    "# 动物：大象、长颈鹿\n",
    "\n",
    "# 句子：鱼缸里的金鱼和乌龟很安静\n",
    "# 动物：金鱼、乌龟\n",
    "\n",
    "# 句子：老虎和猴子在森林里玩耍\n",
    "# 动物："
   ]
  },
  {
   "cell_type": "markdown",
   "id": "826f794e",
   "metadata": {},
   "source": [
    "作用就是通过例子(examples)，统一表述"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e89b5848",
   "metadata": {},
   "source": [
    "# FewShotPromptTemplate结合LLM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ac5a68c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "base_url: https://dashscope.aliyuncs.com/compatible-mode/v1\n",
      "api_key: 35\n",
      "model_name: qwen-plus\n",
      "content='动物：老虎、猴子' additional_kwargs={} response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-plus', 'model_provider': 'openai'} id='lc_run--848c32c5-2e78-43ce-a7f5-c1e97d24d79a'\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from dotenv import load_dotenv\n",
    "load_dotenv()\n",
    "\n",
    "base_url = os.getenv(\"DASHSCOPE_BASE_URL\")\n",
    "api_key = os.getenv(\"DASHSCOPE_API_KEY\")\n",
    "model_name = os.getenv(\"DASHSCOPE_MODEL_NAME\")\n",
    "print(\"base_url:\", base_url)\n",
    "print(\"api_key:\", len(api_key))\n",
    "print(\"model_name:\", model_name)\n",
    "from langchain_openai import ChatOpenAI\n",
    "llm = ChatOpenAI(\n",
    "    model_name=model_name,\n",
    "    openai_api_key=api_key,\n",
    "    openai_api_base=base_url,\n",
    "    streaming=True,\n",
    ")\n",
    "response = llm.invoke(final_prompt)\n",
    "print(response)\n",
    "# 这个例子的作用就是让大模型发现规律，进行实体抽取，提取老虎，猴子"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "d827b9f3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "prompt input_variables=['input'] input_types={} partial_variables={} examples=[{'input': '2鸟3', 'output': '8'}, {'input': '3鸟2', 'output': '9'}, {'input': '5鸟4', 'output': '625'}, {'input': '10鸟3', 'output': '1000'}] example_prompt=PromptTemplate(input_variables=['input', 'output'], input_types={}, partial_variables={}, template='运算式: {input}\\n计算结果: {output}') suffix='已知符号鸟表示特殊运算，请计算：\\n运算式: {input}\\n计算结果:'\n"
     ]
    }
   ],
   "source": [
    "from langchain_core.prompts import PromptTemplate, FewShotPromptTemplate\n",
    "# 1. 定义使用特殊符号#的幂运算示例集合\n",
    "# 用#表示幂运算：a#b = a的b次方\n",
    "examples = [\n",
    "    {\"input\": \"2鸟3\", \"output\": \"8\"},    # 2的3次方 = 8\n",
    "    {\"input\": \"3鸟2\", \"output\": \"9\"},    # 3的2次方 = 9\n",
    "    {\"input\": \"5鸟4\", \"output\": \"625\"},  # 5的4次方 = 625\n",
    "    {\"input\": \"10鸟3\", \"output\": \"1000\"} # 10的3次方 = 1000\n",
    "]\n",
    "\n",
    "# 2. 创建单个示例的模板（明确输入输出格式）\n",
    "example_template = \"运算式: {input}\\n计算结果: {output}\"\n",
    "prompt_sample = PromptTemplate.from_template(example_template)\n",
    "\n",
    "# 3. 创建少样本提示模板（通过示例让模型理解#的含义）\n",
    "prompt = FewShotPromptTemplate(\n",
    "    examples=examples,                # 包含特殊符号#的幂运算示例\n",
    "    example_prompt=prompt_sample,     # 示例的格式模板\n",
    "    # 提示模型理解\"鸟\"的含义并计算新的运算\n",
    "    suffix=\"已知符号鸟表示特殊运算，请计算：\\n运算式: {input}\\n计算结果:\",\n",
    "    input_variables=[\"input\", \"output\"]  # 接收新的运算式和结果变量\n",
    ")\n",
    "print(\"prompt\", prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "562f8b92",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===生成的提示词===\n",
      "text='运算式: 2鸟3\\n计算结果: 8\\n\\n运算式: 3鸟2\\n计算结果: 9\\n\\n运算式: 5鸟4\\n计算结果: 625\\n\\n运算式: 10鸟3\\n计算结果: 1000\\n\\n已知符号鸟表示特殊运算，请计算：\\n运算式: 4鸟5\\n计算结果:'\n"
     ]
    }
   ],
   "source": [
    "\n",
    "# 4. 测试特殊符号的幂运算（例如计算4的5次方）\n",
    "final_prompt = prompt.invoke({\"input\": \"4鸟5\"})\n",
    "print(\"===生成的提示词===\")\n",
    "print(final_prompt)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "42a71ac1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "content='我们来分析这个“鸟”运算的规律。\\n\\n已知：\\n\\n- 2 鸟 3 = 8  \\n- 3 鸟 2 = 9  \\n- 5 鸟 4 = 625  \\n- 10 鸟 3 = 1000  \\n\\n观察这些结果，尝试找出规律。\\n\\n---\\n\\n**第一步：分析每个例子**\\n\\n1. **2 鸟 3 = 8**  \\n   8 = 2³  \\n   所以是 2 的 3 次方\\n\\n2. **3 鸟 2 = 9**  \\n   9 = 3²  \\n   是 3 的 2 次方\\n\\n3. **5 鸟 4 = 625**  \\n   625 = 5⁴？  \\n   5⁴ = 5×5×5×5 = 625 ✅  \\n   是 5 的 4 次方\\n\\n4. **10 鸟 3 = 1000**  \\n   10³ = 1000 ✅  \\n   是 10 的 3 次方\\n\\n---\\n\\n所以可以推测：\\n\\n> a 鸟 b = a^b （a 的 b 次方）\\n\\n验证一下：\\n\\n- 2 鸟 3 = 2³ = 8 ✅  \\n- 3 鸟 2 = 3² = 9 ✅  \\n- 5 鸟 4 = 5⁴ = 625 ✅  \\n- 10 鸟 3 = 10³ = 1000 ✅\\n\\n完全符合！\\n\\n---\\n\\n现在计算：\\n\\n**4 鸟 5 = 4⁵**\\n\\n计算：\\n\\n4⁵ = 4 × 4 × 4 × 4 × 4  \\n= 16 × 16 × 4  \\n= 256 × 4  \\n= **1024**\\n\\n---\\n\\n✅ **答案：1024**' additional_kwargs={} response_metadata={'finish_reason': 'stop', 'model_name': 'qwen-plus', 'model_provider': 'openai'} id='lc_run--73d39e74-cc21-4911-9f37-3f4335dbb483'\n"
     ]
    }
   ],
   "source": [
    "# 我们来看看大模型理解不\n",
    "response = llm.invoke(final_prompt)\n",
    "print(response)\n",
    "# **答案：1024**"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5916d09",
   "metadata": {},
   "source": [
    "# FewShotChatMessagePromptTemplate"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e627fe1b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===格式化后的示例消息===\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Human: 地球围绕什么天体旋转？\\nAI: 地球围绕太阳旋转，这是太阳系的基本运行规律。\\nHuman: 水的化学分子式是什么？\\nAI: 水的化学分子式是H₂O，由2个氢原子和1个氧原子组成。\\nHuman: 一年有几个季节？\\nAI: 一年有4个季节，分别是春季、夏季、秋季和冬季。'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain_core.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate\n",
    "# 1. 示例消息集合（人类提问与AI回答的样本）\n",
    "# 每个示例包含\"input\"（人类提问）和\"output\"（AI回答），用于展示对话模式\n",
    "examples = [\n",
    "    {\"input\": \"地球围绕什么天体旋转？\", \"output\": \"地球围绕太阳旋转，这是太阳系的基本运行规律。\"},\n",
    "    {\"input\": \"水的化学分子式是什么？\", \"output\": \"水的化学分子式是H₂O，由2个氢原子和1个氧原子组成。\"},\n",
    "    {\"input\": \"一年有几个季节？\", \"output\": \"一年有4个季节，分别是春季、夏季、秋季和冬季。\"}\n",
    "]\n",
    "\n",
    "# 2. 定义示例的消息格式模板（指定每条消息的角色）\n",
    "# 通过\"human\"（人类）和\"ai\"（人工智能）角色区分消息来源，统一示例格式\n",
    "msg_example_prompt = ChatPromptTemplate.from_messages([\n",
    "    (\"human\", \"{input}\"),  # 人类角色的消息模板，对应示例中的\"input\"\n",
    "    (\"ai\", \"{output}\")     # AI角色的消息模板，对应示例中的\"output\"\n",
    "])\n",
    "\n",
    "# 3. 创建少样本聊天消息模板（组合所有示例）\n",
    "# 作用：将多个示例按指定格式拼接，形成对话历史样本\n",
    "few_shot_prompt = FewShotChatMessagePromptTemplate(\n",
    "    example_prompt=msg_example_prompt,  # 传入单个示例的格式模板\n",
    "    examples=examples                   # 传入准备好的示例集合\n",
    ")\n",
    "\n",
    "# 4. 输出格式化后的消息列表（可直接作为对话上下文使用）\n",
    "# 格式化后会按顺序生成带角色的消息列表，模拟真实对话历史\n",
    "formatted_messages = few_shot_prompt.format()\n",
    "print(\"===格式化后的示例消息===\")\n",
    "formatted_messages"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "58ceb4a0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "===带角色的示例消息===\n",
      "角色：human，内容：2鸟3是多少？\n",
      "\n",
      "角色：ai，内容：8\n",
      "\n",
      "角色：human，内容：3鸟2是多少？\n",
      "\n",
      "角色：ai，内容：9\n",
      "\n",
      "角色：human，内容：5鸟4是多少？\n",
      "\n",
      "角色：ai，内容：625\n",
      "\n",
      "角色：human，内容：10鸟3是多少？\n",
      "\n",
      "角色：ai，内容：1000\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 这里就是要把角色加入\n",
    "from langchain_core.prompts import HumanMessagePromptTemplate, AIMessagePromptTemplate, FewShotChatMessagePromptTemplate\n",
    "# 1. 定义使用特殊符号#的幂运算示例集合\n",
    "# 用#表示幂运算：a#b = a的b次方\n",
    "examples = [\n",
    "    {\"input\": \"2鸟3\", \"output\": \"8\"},    # 2的3次方 = 8\n",
    "    {\"input\": \"3鸟2\", \"output\": \"9\"},    # 3的2次方 = 9\n",
    "    {\"input\": \"5鸟4\", \"output\": \"625\"},  # 5的4次方 = 625\n",
    "    {\"input\": \"10鸟3\", \"output\": \"1000\"} # 10的3次方 = 1000\n",
    "]\n",
    "# 2. 定义单轮对话的模板（人类提问 + AI回答）\n",
    "# 第一步：创建单个角色的消息模板\n",
    "human_prompt = HumanMessagePromptTemplate.from_template(\"{input}是多少？\")\n",
    "ai_prompt = AIMessagePromptTemplate.from_template(\"{output}\")\n",
    "\n",
    "# 第二步：用 ChatPromptTemplate 把两个模板包装成「单轮对话模板」\n",
    "# 这样得到的是单个 BaseChatPromptTemplate 实例，符合 example_prompt 要求\n",
    "single_turn_prompt = ChatPromptTemplate.from_messages(\n",
    "    [\n",
    "        human_prompt,  # 人类角色消息\n",
    "        ai_prompt      # AI角色消息\n",
    "    ]\n",
    ")\n",
    "\n",
    "# 3. 创建少样本聊天模板（传入包装后的单轮对话模板）\n",
    "few_shot_prompt = FewShotChatMessagePromptTemplate(\n",
    "    examples=examples,\n",
    "    example_prompt=single_turn_prompt,  # 现在是单个 BaseChatPromptTemplate 实例\n",
    ")\n",
    "\n",
    "# 4. 生成带角色的消息列表\n",
    "formatted_messages = few_shot_prompt.format_messages()\n",
    "# 打印结果（验证角色和内容）\n",
    "print(\"===带角色的示例消息===\")\n",
    "for msg in formatted_messages:\n",
    "    print(f\"角色：{msg.type}，内容：{msg.content}\\n\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "e5cd9a0e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "langchain_core.messages.human.HumanMessage"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "type(formatted_messages[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2afd623a",
   "metadata": {},
   "outputs": [],
   "source": [
    "\"已知符号鸟表示特殊运算，请计算：\\n运算式: {input}\\n计算结果:\","
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "langchain-course (3.10.12)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
